package com.kay.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kay.anno.RPCServer;
import com.kay.common.RPCRequest;
import com.kay.common.RPCResponse;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.springframework.beans.BeansException;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description: 服务端业务处理类
 * 1.将标有@RpcService注解的bean缓存
 * 2.接收客户端请求
 * 3.根据传递过来的beanName从缓存中查找到对应的bean
 * 4.解析请求中的方法名称. 参数类型 参数信息
 * 5.反射调用bean的方法
 * 6.给客户端进行响应
 * @Author: Kay
 * @CreateDate: 2021/8/27$ 18:33$
 * @UpdateUser: Kay
 * @UpdateDate: 2021/8/27$ 18:33$
 */
@Component
@ChannelHandler.Sharable
public class RPCServerHandler extends SimpleChannelInboundHandler<String> implements ApplicationContextAware {
    // 所有注解有 @RPCServer Bean对象
    private static final Map<String, Object> serverInstanceMap = new ConcurrentHashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("对象初始化 ~~~~~~~~~~~~ ");
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(RPCServer.class);
        if (beansWithAnnotation != null && beansWithAnnotation.size() > 0) {
            for (Map.Entry<String, Object> entry : beansWithAnnotation.entrySet()) {
                Object objectServer = entry.getValue();
                // 判断是否有对应的接口
                if (objectServer.getClass().getInterfaces() == null) {
                    throw new RuntimeException("服务必须有对应的实现类");
                }
                // 按照 key 为objectServer实现的第一个接口类的类路径，value 为objectServer
                serverInstanceMap.put(objectServer.getClass().getInterfaces()[0].getName(), objectServer);
            }
        }
    }

    /**
     * 接收客户端请求，返回响应结果
     *
     * @param channelHandlerContext
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
        System.out.println(" 服务端接收到的消息 msg" + msg);
        RPCRequest request = JSON.parseObject(msg, RPCRequest.class);
        RPCResponse response = new RPCResponse();
        response.setRequestId(request.getRequestId());
        try {
            response.setResult(handleRequest(request));
        } catch (Exception exception) {
            response.setError(exception.getMessage());
            exception.printStackTrace();
        }
        channelHandlerContext.writeAndFlush(JSON.toJSONString(response));

    }

    /**
     * 处理RPC请求
     *
     * @param request
     * @return
     */
    public Object handleRequest(RPCRequest request) throws InvocationTargetException {
        System.out.println("开始处理request请求 " + request);
        String className = request.getClassName();
        Object object = serverInstanceMap.get(className);
        if (object == null) {
            return new RuntimeException("根据 beanName：[ " + className + " ]找不到对应服务");
        }

        // CGLib反射调用
        FastClass fastClass = FastClass.create(object.getClass());
        FastMethod method = fastClass.getMethod(request.getMethodName(), request.getParameterTypes());
        return method.invoke(object, request.getParameters());
    }

}
